using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Collision;


namespace Utilities
{
    public static class PhysicsHelper
    {
        static Vector3 _Pos;
        static Matrix _Heading;
        static float _Mass;
        static Vector3 _Vel;
        static Action<CollisionSkin> fill_collision_skins;
        static Action<Body> initialize_body = new Action<Body>(
            body =>
            {
                var collision = body.CollisionSkin;
                if (collision == null)
                    collision = new CollisionSkin(body);
                collision.Reset(body);
                fill_collision_skins(collision);
                body.CollisionSkin = collision;
                body.Mass = _Mass;
                body.MoveTo(_Pos, _Heading);
                body.Velocity = _Vel;
            });

        public static Body create_physics_body(Vector3 _Pos, Matrix _Heading, float _Mass, Vector3 _Vel, Action<CollisionSkin> fill_collision_skins)
        {
            PhysicsHelper._Pos = _Pos;
            PhysicsHelper._Heading = _Heading;
            PhysicsHelper._Mass = _Mass;
            PhysicsHelper._Vel = _Vel;
            PhysicsHelper.fill_collision_skins = fill_collision_skins;
            return PhysicsSystem.CurrentPhysicsSystem.AddBody(initialize_body);
        }

        static MaterialProperties default_properties = new MaterialProperties(0.5f, 0.7f, 0.6f);
        static ArrayList<BoundingSphere> _Children;
        static Action<CollisionSkin> initialize_collision_skin_with_children = new Action<CollisionSkin>(
            collision =>
            {
                for (int i = 0; i < _Children.Count; i++)
                {
                    var c = _Children[i];
                    collision.AddPrimitive(new Sphere(c.Center, c.Radius), default_properties);
                }
                if (non_collidables != null)
                    for (int i = 0; i < non_collidables.Count; i++)
                    {
                        non_collidables[i].CollisionSkin.NonCollidables.Add(collision);
                        collision.NonCollidables.Add(non_collidables[i].CollisionSkin);
                    }
            });

        public static Body create_spheres(Vector3 _Pos, BoundingSphere _Parent, ArrayList<BoundingSphere> _Children, float _Mass)
        {
            var _Radius = _Parent.Radius;
            PhysicsHelper._Children = _Children;
            if (non_collidables!=null)
                non_collidables.Clear();
            return create_physics_body(_Pos, Matrix.Identity, _Mass, Vector3.Zero, initialize_collision_skin_with_children);
        }

        static ArrayList<Body> no_non_collidables = new ArrayList<Body>();
        public static Body create_sphere(BoundingSphere _Parent, Vector3 _Vel, float _Mass)
        {
            return create_sphere(_Parent, _Vel, _Mass, no_non_collidables);
        }

        static float _Radius;
        static ArrayList<Body> non_collidables;
        static Action<CollisionSkin> initialize_non_collidables = new Action<CollisionSkin>(
            collision =>
            {
                collision.AddPrimitive(new Sphere(Vector3.Zero, _Radius), default_properties);
                if (non_collidables != null)
                    for(int i = 0; i < non_collidables.Count; i++)
                    {
                        non_collidables[i].CollisionSkin.NonCollidables.Add(collision);
                        collision.NonCollidables.Add(non_collidables[i].CollisionSkin);
                    }
            });

        public static Body create_sphere(BoundingSphere _Parent, Vector3 _Vel, float _Mass, ArrayList<Body> non_collidables)
        {
            var _Pos = _Parent.Center;
            _Radius = _Parent.Radius;
            var orientation = Matrix.Identity;
            PhysicsHelper.non_collidables = non_collidables;
            return create_physics_body(_Pos, orientation, _Mass, _Vel, initialize_non_collidables);
        }

        public static Body create_spheres(Vector3 _Pos, BoundingSphere _Parent, ArrayList<BoundingSphere> _Children, float _Mass, ArrayList<Body> non_collidables)
        {
            var _Radius = _Parent.Radius;
            PhysicsHelper._Children = _Children;
            PhysicsHelper.non_collidables = non_collidables;
            return create_physics_body(_Pos, Matrix.Identity, _Mass, Vector3.Zero, initialize_collision_skin_with_children);
        }

        public static Body create_projectile(Vector3 _Pos, float _Radius, Matrix _Heading, float _Speed, float _Mass, ArrayList<Body> non_collidables)
        {
            PhysicsHelper._Radius = _Radius;
            PhysicsHelper.non_collidables = non_collidables;
            return create_physics_body(_Pos, _Heading, _Mass, _Heading.Forward * _Speed, initialize_non_collidables);
        }
        
        public static bool find_simple_collision(this Body body1, Body body2)
        {
            var b1 = body1.bounding_sphere();
            b1.Center += body1.Position;
            var b2 = body2.bounding_sphere();
            b2.Center += body2.Position;
            return b1.Intersects(b2);
        }
        //public static Vector3 getLastCollisionPoint()
        //{
        //    return collisonPoint;
        //}

    }
}
